Executive Summary
The National Institute of Health (NIH) National Center for Advancing Translational Sciences (NCATS) collaborated on a study to explore mouse development in the dorsal root ganglia. Five time points were collected throughout development.
For this analysis, Rancho proposes to run Cell Ranger to align, filter, count barcodes, count UMI and aggregate multiple runs of Cell Ranger count if necessary. Rancho will review and troubleshoot the Seurat workflow for all time points and identify the optimal resolution for clustering. There may be a higher than normal number of doublet droplets; therefore, we will run the created Seurat object through DoubletFinder. We will estimate the predicted doublets in the dataset in comparison to the Seurat object without running DoubletFinder. After running DoubletFinder, we will perform differential gene expression analysis using Seurat and over-representation analysis using the Broad Institute’s GSEA program. Lastly, we will run Slingshot to build single-cell trajectories using pseudotime.
Solution
Processing FASTQ to produce UMI counts
Single cell feature counts for a single library were generated using the following cellranger count script. This was performed by first downloading a current prebuilt reference library for mus musculus mm10 assembly.
wget https://cf.10xgenomics.com/supp/cell-exp/refdata-gex-mm10-2020-A.tar.gz
code/run-cellranger-count.sh
Results from cellrange count quanlity summary metrics indicated that all samples were good quality and suitable for downstream analysis.
Table 1 - Cell Ranger Count Summary Stats
| 082120DRG |
11,198 |
53,351 |
2,290 |
87.3% |
| 101920DRG |
11,926 |
77,566 |
2,491 |
93.3% |
| 103020DRG |
9,876 |
64,663 |
3,350 |
92.7% |
| 110220DRG |
8,342 |
62,208 |
3,275 |
93.1% |
| 111220DRG |
15,515 |
54,126 |
2,670 |
93.2% |
Seurat sample preprocessing
In order to facilitate streamlined preprocessing of individual sample each was subject to import, calculation of percent mitochodrial content per cell, application of cutoffs related to umi counts and mito content, scaleing and normalization. These operations were applied using the seurat-processor.Rmd through code/01b-render-all-seurat-processors.R. This allows not only consistent processing settings but also sample-specific logging along with customized diagnostic plots.
Since sequencing operations on each sample are nonstandard, filtering criteria were configured using config.yml. This includes min/max cutoffs for nFeature_RNA and percent.mt in addition to number of umap dimensions for clustering and cluster resolution.
Outputs preprocesing reports can be found at:
data/seurat-preprocesing-reports/
├── filtering-082120DRG.html
├── filtering-101920DRG.html
├── filtering-103020DRG.html
├── filtering-110220DRG.html
└── filtering-111220DRG.html
0 directories, 5 files
Doublet detection
Based on information from the Dr. Hoke’s lab and NCATS, it is possible that experimentalists may have overloaded the chip, potentially producing excessive doublet droplets (droplets with more than one cell). To determine if doublets were problematic in the dataset, we utilized the DoubletFinder package in R.
The DoubletFinder method includes 4 distinct steps:
- Generate artificial doublets from existing scRNA-seq data
- Pre-process merged real-artificial data
- Perform PCA and use the PC distance matrix to find each cell’s proportion of artificial k nearest neighbors (pANN)
- Rank order and threshold pANN values according to the expected number of doublets
Following recommended steps from this package, individual samples were imported as Seurat objects, normalized and scaled before applying the DoubleFinder methods. 02-doublet-finder.R was run interactively for all 5 samples in order to optimize pK and nExp. This included a pN-pK parameter sweeps on a 10,000-cell subset of a pre-processed Seurat object. Will use all cells if Seurat object contains less than 10,000 cells. Results are fed into summarizeSweep() and find.pK() functions during optimal pK parameter selection workflow. Parameters tested: pN = 0.05-0.3, pK = 0.0005-0.3
Results from the Doublet Finder algorithm did not successfully identify any likely doublet cells. The analysis was confirmed with two separate approaches: with and without estimation of homotypic doublet cells. Since DoubletFinder is insensitive to homotypic doublets the estimation process is entirely based on estimated frequency within clusters, and highly subject to input parameters. The package authors consider doublet number estimates based on Poisson statistics with and without homotypic doublet proportion adjustment to ‘bookend’ the real detectable doublet rate, however in these cases where we see a range from 0 (without homotypic) through 25% cell count (the value used to estimate homotypic populations) that this package has identified no actual doublets. In response to this finding we are proceeding with this analysis without adjusting for doublet species cells. Full results can be found on individual doublet finder reports.
data/doublet-finder-reports/
├── 082120DRG.html
├── 101920DRG.html
├── 103020DRG.html
├── 110220DRG.html
└── 111220DRG.html
0 directories, 5 files
Main Seurat object processor
After individual samples were ingested, filtered and considered for doublet exclusion they were aggregated into a single seurat object and normalized. This process was implemented as code/01c-merge.R. Processing included the following major steps:
- Merge into a single seurat
- Score each cell for S and G2M cell cycle effects that are included in the regression/normalization steps. See
code/cell-cycle-testing.R and Apr 1, 2021 presentation for details.
- NormalizeData, FindVariableFeatures, ScaleData
- RunPCA followed by Elbow plot to identify important principal components
- RunUMAP follwed by DimPlot
- Identify optimal cluster resolution using clustree
- Output from this main processing is stored as
objects/filtered-merged-umap.RDS
Differential expression
Once an optimal Seurat resolution had been selected (0.03), we ran differential gene expression analysis in Seurat using the FindMarkers function in Seurat. This was performed for each cluster in a cluster-vs-all contrast model. Since a list of targeted genes was not explicitly provided we report the top 20 genes per cluster.
ls data/plots/dex-top-dotplot*
data/plots/dex-top-dotplot_COMBINED.png
data/plots/dex-top-dotplot_cluster-0.png
data/plots/dex-top-dotplot_cluster-1.png
data/plots/dex-top-dotplot_cluster-2.png
data/plots/dex-top-dotplot_cluster-3.png
data/plots/dex-top-dotplot_cluster-4.png
data/plots/dex-top-dotplot_cluster-5.png
data/plots/dex-top-dotplot_cluster-6.png
data/plots/dex-top-dotplot_cluster-7.png
data/plots/dex-top-dotplot_cluster-8.png
General enrichment analysis
We followed-up the DGE analysis with over-representation analysis using msigdb and clusterprofiler in R exploring the GO gene sets and KEGG. This work was defined by the code/06-enrichr.R script and includes msigdb categories “KEGG”, “C5”(Go terms) as well as modules defined for the iPSC cluster profiler tool at NCATs. Results are summarized on the data/table/enriched-sets.tsv
read_tsv("data/tables/enriched-sets.tsv", col_types = cols(
cluster = col_double(),
hits = col_double(),
ID = col_character(),
Description = col_character(),
GeneRatio = col_character(),
BgRatio = col_character(),
pvalue = col_double(),
p.adjust = col_double(),
qvalue = col_double(),
geneID = col_character(),
Count = col_double() )) %>%
slice(1:10) %>%
select(-geneID)
ls data/plots/go*
ls data/plots/kegg*
data/plots/go-NEURO-heatmap.png
data/plots/go-heatmap.png
data/plots/kegg-heatmap.png
Module conversion and scoring
Lastly, to better understand the identity or cell type for each cluster, we ran Seurat’s AddModuleScore function, using NCATS’ list of known cell markers from a previously created iPSC profiler for each cell separation approach. The AddModuleScore calculates the average expression for each cluster subtracted by the aggregated expression of control feature sets. Positive expression levels indicate a higher expression level than random. We will use the expression levels to broadly assign each cluster to potential identities (cell type).
ls data/plots/ipsc*
data/plots/ipsc-feature-plots-1.png
data/plots/ipsc-feature-plots-2.png
data/plots/ipsc-feature-plots-3.png
data/plots/ipsc-feature-plots-4.png
data/plots/ipsc-feature-plots-5.png
data/plots/ipsc-feature-plots-Calponin3.png
data/plots/ipsc-feature-plots-DRG-Markers.png
data/plots/ipsc-feature-plots-S100a8.png
data/plots/ipsc-feature-plots-SGC.png
data/plots/ipsc-feature-plots-cluster0.png
data/plots/ipsc-feature-plots-cluster1.png
data/plots/ipsc-feature-plots-cluster5.png
data/plots/ipsc-module-heatmap-Median.png
data/plots/ipsc-violin-plots-1.png
data/plots/ipsc-violin-plots-2.png
data/plots/ipsc-violin-plots-3.png
data/plots/ipsc-violin-plots-4.png
data/plots/ipsc-violin-plots-5.png
data/plots/ipsc-violin-plots-Calponin3.png
data/plots/ipsc-violin-plots-SGC.png
data/plots/ipsc-violin-plots-cluster0.png
data/plots/ipsc-violin-plots-cluster1.png
data/plots/ipsc-violin-plots-cluster5.png
Trajectory inference
Lastly, we ran Slingshot for single-cell trajectory analysis. The goal of slingshot is to use clusters of cells to uncover global structure and convert these to pseudotime. To accomplish this work we utilized the dynverse set of R-packages in conjunction with provided code from Claire Malley to run Slingshot and extract pseudotime metrics.
This analysis yielded some productive findings across the annotated umap clusters. This roughly followed a trajectory along neuronal precursors (cluster 1), glial/astral/SGC cells (cluster 0, the largest) and splits into several types of maturing nociceptors (cluster 5) and likely alternative developmental neuronal cell types (clusters 3,6)
When an unsupervised pseudotime estimation is plotted on these cells we see a natural progression.

Pseudotype-based differential modeling
After Slingshot was run, we explored temporally expressed genes using the tradeSeq package. For each gene, we fit a general additive model (GAM) using a negative binomial noise distribution to model relationships between gene expression and pseudotime. After running the GAM model, we tested for significant associations between expression and pseudotime using the associationTest.
LS0tCnRpdGxlOiAic2NSTkEtU2VxIEFuYWx5c2lzIG9mIE1vdXNlIERldmVsb3BtZW50IgphdXRob3I6ICJEYW4gUm96ZWxsZSIKZGF0ZTogIjQvMi8yMDIxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIEV4ZWN1dGl2ZSBTdW1tYXJ5IAoKVGhlIE5hdGlvbmFsIEluc3RpdHV0ZSBvZiBIZWFsdGggKE5JSCkgTmF0aW9uYWwgQ2VudGVyIGZvciBBZHZhbmNpbmcgVHJhbnNsYXRpb25hbCBTY2llbmNlcyAoTkNBVFMpIGNvbGxhYm9yYXRlZCBvbiBhIHN0dWR5IHRvIGV4cGxvcmUgbW91c2UgZGV2ZWxvcG1lbnQgaW4gdGhlIGRvcnNhbCByb290IGdhbmdsaWEuIEZpdmUgdGltZSBwb2ludHMgd2VyZSBjb2xsZWN0ZWQgdGhyb3VnaG91dCBkZXZlbG9wbWVudC4gICAKCkZvciB0aGlzIGFuYWx5c2lzLCBSYW5jaG8gcHJvcG9zZXMgdG8gcnVuIENlbGwgUmFuZ2VyIHRvIGFsaWduLCBmaWx0ZXIsIGNvdW50IGJhcmNvZGVzLCBjb3VudCBVTUkgYW5kIGFnZ3JlZ2F0ZSBtdWx0aXBsZSBydW5zIG9mIENlbGwgUmFuZ2VyIGNvdW50IGlmIG5lY2Vzc2FyeS4gUmFuY2hvIHdpbGwgcmV2aWV3IGFuZCB0cm91Ymxlc2hvb3QgdGhlIFNldXJhdCB3b3JrZmxvdyBmb3IgYWxsIHRpbWUgcG9pbnRzIGFuZCBpZGVudGlmeSB0aGUgb3B0aW1hbCByZXNvbHV0aW9uIGZvciBjbHVzdGVyaW5nLiBUaGVyZSBtYXkgYmUgYSBoaWdoZXIgdGhhbiBub3JtYWwgbnVtYmVyIG9mIGRvdWJsZXQgZHJvcGxldHM7IHRoZXJlZm9yZSwgd2Ugd2lsbCBydW4gdGhlIGNyZWF0ZWQgU2V1cmF0IG9iamVjdCB0aHJvdWdoIERvdWJsZXRGaW5kZXIuIFdlIHdpbGwgZXN0aW1hdGUgdGhlIHByZWRpY3RlZCBkb3VibGV0cyBpbiB0aGUgZGF0YXNldCBpbiBjb21wYXJpc29uIHRvIHRoZSBTZXVyYXQgb2JqZWN0IHdpdGhvdXQgcnVubmluZyBEb3VibGV0RmluZGVyLiBBZnRlciBydW5uaW5nIERvdWJsZXRGaW5kZXIsIHdlIHdpbGwgcGVyZm9ybSBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzIHVzaW5nIFNldXJhdCBhbmQgb3Zlci1yZXByZXNlbnRhdGlvbiBhbmFseXNpcyB1c2luZyB0aGUgQnJvYWQgSW5zdGl0dXRl4oCZcyBHU0VBIHByb2dyYW0uIExhc3RseSwgd2Ugd2lsbCBydW4gU2xpbmdzaG90IHRvIGJ1aWxkIHNpbmdsZS1jZWxsIHRyYWplY3RvcmllcyB1c2luZyBwc2V1ZG90aW1lLiAgCgojIyBJbnB1dCBkYXRhIAoKQ2hyb21pdW0gU2luZ2xlIENlbGwgc2VxdWVuY2luZyB1c2luZyB0aGUgaTcgc2luZ2xlIGluZGV4IHBsYXRlcyB3ZXJlIHByb3ZpZGVkIGFzIDE2MCBpbmRpdmlkdWFsIHBhaXJlZC1lbmQgRkFTVFEgZmlsZXMuIEZpdmUgZGlzdGluY3Qgc2FtcGxlcyB3ZXJlIGluZGV4ZWQgYWNjb3JkaW5nIHRvIFRhYmxlIEkgYW5kIHNlcXVlbmNlZCB1c2luZyA0IGJhcmNvZGUgc2VxdWVuY2VzLCB3aGljaCBoYXZlIGJhbGFuY2VkIGJhc2UgY29tcG9zaXRpb24uIEVhY2ggb2YgdGhlc2UgYmFyY29kZXMgd2FzIHNlcXVlbmNlZCBhY3Jvc3MgNCBsYW5lcy4gKDUgc2FtcGxlcyAqIDQgYmFyY29kZXMgKiA0IGxhbmVzICogMiBlbmRzID0gMTYwIGZpbGVzKQoKIyMjIyAqKlNhbXBsZSBzaGVldCoqCgpTYW1wbGUgICAgfEk3X0luZGV4X0lECXxCYXJjb2Rlcwo6LS0tLS0tLS0tIHwgOi0tLS0tLS0tLQl8IDotLS0tLS0tLQowODIxMjBEUkcgfCBTSS1HQS1HMQl8IEFUR0FBVENULEdBVENUQ0FHLENDQUdHQUdDLFRHQ1RDR1RBCjEwMTkyMERSRyB8IFNJLUdBLUc5CXwgVEFHR0FDR1QsQVRDQ0NBQ0EsR0dBQVRHVEMsQ0NUVEdUQUcKMTAzMDIwRFJHIHwgU0ktR0EtQzkJfCBHQ0dDQUdBQSxBVENUVEFDQyxUQVRHR1RHVCxDR0FBQ0NURwoxMTAyMjBEUkcgfCBTSS1HQS1EOQl8IEFHR0FHQVRHLEdBVEdUR0dULENUQUNBVENDLFRDQ1RDQ0FBCjExMTIyMERSRyB8IFNJLUdBLUg5CXwgQUNBQ1RHVFQsQ0FHR0FUR0csR0dDVEdBQUMsVFRUQUNDQ0EKCldoaWxlIGV4cGxpY2l0IHNhbXBsZSBwcmVwYXJhdGlvbiBpbmZvcm1hdGlvbiB3YXMgbm90IHByb3ZpZGVkLCBpdCBoYXMgYmVlbiBpbmZlcnJlZCBmcm9tIHRoZSBzYW1wbGUgbGFiZWxpbmcgYW5kIHB1YmxpY2F0aW9ucyBmcm9tIHRoZSBzb3VyY2UgbGFib3JhdG9yeSAoQWhtZXQgSG9rZSkgdGhhdCB0aGVzZSBhcmUgcHVyaWZpZWQgZG9yc2FsIHJvb3QgZ2FuZ2xpYSBleHBsYW50IHNhbXBsZXMgZnJvbSBoZWFsdGh5IG1pY2UgYXQgNSB0aW1lLXBvaW50cyBhY3Jvc3MgMTItd2Vla3MgKHVua25vd24gc3RhcnRpbmcgc3RhdHVzKS4KCiMgU29sdXRpb24KCiMjIFByb2Nlc3NpbmcgRkFTVFEgdG8gcHJvZHVjZSBVTUkgY291bnRzCgpTaW5nbGUgY2VsbCBmZWF0dXJlIGNvdW50cyBmb3IgYSBzaW5nbGUgbGlicmFyeSB3ZXJlIGdlbmVyYXRlZCB1c2luZyB0aGUgZm9sbG93aW5nIGNlbGxyYW5nZXIgY291bnQgc2NyaXB0LiBUaGlzIHdhcyBwZXJmb3JtZWQgYnkgZmlyc3QgZG93bmxvYWRpbmcgYSBjdXJyZW50IHByZWJ1aWx0IHJlZmVyZW5jZSBsaWJyYXJ5IGZvciBbKm11cyBtdXNjdWx1cyogbW0xMF0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS9zaW5nbGUtY2VsbC1nZW5lLWV4cHJlc3Npb24vc29mdHdhcmUvZG93bmxvYWRzL2xhdGVzdCkgYXNzZW1ibHkuCgpgYGAKd2dldCBodHRwczovL2NmLjEweGdlbm9taWNzLmNvbS9zdXBwL2NlbGwtZXhwL3JlZmRhdGEtZ2V4LW1tMTAtMjAyMC1BLnRhci5negpjb2RlL3J1bi1jZWxscmFuZ2VyLWNvdW50LnNoCmBgYAoKUmVzdWx0cyBmcm9tIGNlbGxyYW5nZSBjb3VudCBxdWFubGl0eSBzdW1tYXJ5IG1ldHJpY3MgaW5kaWNhdGVkIHRoYXQgYWxsIHNhbXBsZXMgd2VyZSBnb29kIHF1YWxpdHkgYW5kIHN1aXRhYmxlIGZvciBkb3duc3RyZWFtIGFuYWx5c2lzLgoKIyMjIyAqKlRhYmxlIDEgLSBDZWxsIFJhbmdlciBDb3VudCBTdW1tYXJ5IFN0YXRzKioKClNhbXBsZSAgICB8RXN0LiBDZWxsIE51bWJlciB8TWVhbiBSZWFkcyAvIENlbGwgICAgfE1lZGlhbiBHZW5lcyAvIENlbGwgICB8UmVhZHMgTWFwcGVkIENvbmZpZGVudGx5IHRvIEdlbm9tZSAgICAgICAgIAo6LS0tLS0tLS0tfDotLS0tLS0tLS0gICAgICAgfDotLS0tLS0tLS0gICAgICAgICAgIHw6LS0tLS0tLS0tLS0tLS0tLSAgICAgfDotLS0tICAgICAgICAgICAgCjA4MjEyMERSRyB8IDExLDE5OCAgICAgICAgICB8IDUzLDM1MSAgICAgICAgICAgICAgfDIsMjkwICAgICAgICAgICAgICAgICB8IDg3LjMlCjEwMTkyMERSRyB8IDExLDkyNiAgICAgICAgICB8IDc3LDU2NiAgICAgICAgICAgICAgfDIsNDkxICAgICAgICAgICAgICAgICB8IDkzLjMlCjEwMzAyMERSRyB8IDksODc2ICAgICAgICAgICB8IDY0LDY2MyAgICAgICAgICAgICAgfDMsMzUwICAgICAgICAgICAgICAgICB8IDkyLjclCjExMDIyMERSRyB8IDgsMzQyICAgICAgICAgICB8IDYyLDIwOCAgICAgICAgICAgICAgfDMsMjc1ICAgICAgICAgICAgICAgICB8IDkzLjElCjExMTIyMERSRyB8IDE1LDUxNSAgICAgICAgICB8IDU0LDEyNiAgICAgICAgICAgICAgfDIsNjcwICAgICAgICAgICAgICAgICB8IDkzLjIlCgojIyBTZXVyYXQgc2FtcGxlIHByZXByb2Nlc3NpbmcKCkluIG9yZGVyIHRvIGZhY2lsaXRhdGUgc3RyZWFtbGluZWQgcHJlcHJvY2Vzc2luZyBvZiBpbmRpdmlkdWFsIHNhbXBsZSBlYWNoIHdhcyBzdWJqZWN0IHRvIGltcG9ydCwgY2FsY3VsYXRpb24gb2YgcGVyY2VudCBtaXRvY2hvZHJpYWwgY29udGVudCBwZXIgY2VsbCwgYXBwbGljYXRpb24gb2YgY3V0b2ZmcyByZWxhdGVkIHRvIHVtaSBjb3VudHMgYW5kIG1pdG8gY29udGVudCwgc2NhbGVpbmcgYW5kIG5vcm1hbGl6YXRpb24uIFRoZXNlIG9wZXJhdGlvbnMgd2VyZSBhcHBsaWVkIHVzaW5nIHRoZSBgYGBzZXVyYXQtcHJvY2Vzc29yLlJtZGBgYCB0aHJvdWdoIGBgYGNvZGUvMDFiLXJlbmRlci1hbGwtc2V1cmF0LXByb2Nlc3NvcnMuUmBgYC4gVGhpcyBhbGxvd3Mgbm90IG9ubHkgY29uc2lzdGVudCBwcm9jZXNzaW5nIHNldHRpbmdzIGJ1dCBhbHNvIHNhbXBsZS1zcGVjaWZpYyBsb2dnaW5nIGFsb25nIHdpdGggY3VzdG9taXplZCBkaWFnbm9zdGljIHBsb3RzLiAKClNpbmNlIHNlcXVlbmNpbmcgb3BlcmF0aW9ucyBvbiBlYWNoIHNhbXBsZSBhcmUgbm9uc3RhbmRhcmQsIGZpbHRlcmluZyBjcml0ZXJpYSB3ZXJlIGNvbmZpZ3VyZWQgdXNpbmcgYGBgY29uZmlnLnltbGBgYC4gVGhpcyBpbmNsdWRlcyBtaW4vbWF4IGN1dG9mZnMgZm9yIG5GZWF0dXJlX1JOQSBhbmQgcGVyY2VudC5tdCBpbiBhZGRpdGlvbiB0byBudW1iZXIgb2YgdW1hcCBkaW1lbnNpb25zIGZvciBjbHVzdGVyaW5nIGFuZCBjbHVzdGVyIHJlc29sdXRpb24uCgpPdXRwdXRzIHByZXByb2Nlc2luZyByZXBvcnRzIGNhbiBiZSBmb3VuZCBhdDoKCmBgYHtiYXNoIGVjaG89RkFMU0V9CnRyZWUgZGF0YS9zZXVyYXQtcHJlcHJvY2VzaW5nLXJlcG9ydHMvCmBgYAoKIyMgRG91YmxldCBkZXRlY3Rpb24KCkJhc2VkIG9uIGluZm9ybWF0aW9uIGZyb20gdGhlIERyLiBIb2tl4oCZcyBsYWIgYW5kIE5DQVRTLCBpdCBpcyBwb3NzaWJsZSB0aGF0IGV4cGVyaW1lbnRhbGlzdHMgbWF5IGhhdmUgb3ZlcmxvYWRlZCB0aGUgY2hpcCwgcG90ZW50aWFsbHkgcHJvZHVjaW5nIGV4Y2Vzc2l2ZSBkb3VibGV0IGRyb3BsZXRzIChkcm9wbGV0cyB3aXRoIG1vcmUgdGhhbiBvbmUgY2VsbCkuIFRvIGRldGVybWluZSBpZiBkb3VibGV0cyB3ZXJlIHByb2JsZW1hdGljIGluIHRoZSBkYXRhc2V0LCB3ZSB1dGlsaXplZCB0aGUgW0RvdWJsZXRGaW5kZXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9jaHJpcy1tY2dpbm5pcy11Y3NmL0RvdWJsZXRGaW5kZXIpIHBhY2thZ2UgaW4gUi4gCgpUaGUgRG91YmxldEZpbmRlciBtZXRob2QgaW5jbHVkZXMgNCBkaXN0aW5jdCBzdGVwczoKCjEuIEdlbmVyYXRlIGFydGlmaWNpYWwgZG91YmxldHMgZnJvbSBleGlzdGluZyBzY1JOQS1zZXEgZGF0YQoyLiBQcmUtcHJvY2VzcyBtZXJnZWQgcmVhbC1hcnRpZmljaWFsIGRhdGEKMy4gUGVyZm9ybSBQQ0EgYW5kIHVzZSB0aGUgUEMgZGlzdGFuY2UgbWF0cml4IHRvIGZpbmQgZWFjaCBjZWxsJ3MgcHJvcG9ydGlvbiBvZiBhcnRpZmljaWFsIGsgbmVhcmVzdCBuZWlnaGJvcnMgKHBBTk4pCjQuIFJhbmsgb3JkZXIgYW5kIHRocmVzaG9sZCBwQU5OIHZhbHVlcyBhY2NvcmRpbmcgdG8gdGhlIGV4cGVjdGVkIG51bWJlciBvZiBkb3VibGV0cwoKRm9sbG93aW5nIHJlY29tbWVuZGVkIHN0ZXBzIGZyb20gdGhpcyBwYWNrYWdlLCBpbmRpdmlkdWFsIHNhbXBsZXMgd2VyZSBpbXBvcnRlZCBhcyBTZXVyYXQgb2JqZWN0cywgbm9ybWFsaXplZCBhbmQgc2NhbGVkIGJlZm9yZSBhcHBseWluZyB0aGUgRG91YmxlRmluZGVyIG1ldGhvZHMuIGBgYDAyLWRvdWJsZXQtZmluZGVyLlJgYGAgd2FzIHJ1biBpbnRlcmFjdGl2ZWx5IGZvciBhbGwgNSBzYW1wbGVzIGluIG9yZGVyIHRvIG9wdGltaXplIHBLIGFuZCBuRXhwLiBUaGlzIGluY2x1ZGVkIGEgcE4tcEsgcGFyYW1ldGVyIHN3ZWVwcyBvbiBhIDEwLDAwMC1jZWxsIHN1YnNldCBvZiBhIHByZS1wcm9jZXNzZWQgU2V1cmF0IG9iamVjdC4gV2lsbCB1c2UgYWxsIGNlbGxzIGlmIFNldXJhdCBvYmplY3QgY29udGFpbnMgbGVzcyB0aGFuIDEwLDAwMCBjZWxscy4gUmVzdWx0cyBhcmUgZmVkIGludG8gYGBgc3VtbWFyaXplU3dlZXAoKWBgYCBhbmQgYGBgZmluZC5wSygpYGBgIGZ1bmN0aW9ucyBkdXJpbmcgb3B0aW1hbCBwSyBwYXJhbWV0ZXIgc2VsZWN0aW9uIHdvcmtmbG93LiBQYXJhbWV0ZXJzIHRlc3RlZDogcE4gPSAwLjA1LTAuMywgcEsgPSAwLjAwMDUtMC4zCgoqKlJlc3VsdHMqKiBmcm9tIHRoZSBEb3VibGV0IEZpbmRlciBhbGdvcml0aG0gZGlkIG5vdCBzdWNjZXNzZnVsbHkgaWRlbnRpZnkgYW55IGxpa2VseSBkb3VibGV0IGNlbGxzLiBUaGUgYW5hbHlzaXMgd2FzIGNvbmZpcm1lZCB3aXRoIHR3byBzZXBhcmF0ZSBhcHByb2FjaGVzOiB3aXRoIGFuZCB3aXRob3V0IGVzdGltYXRpb24gb2YgaG9tb3R5cGljIGRvdWJsZXQgY2VsbHMuIFNpbmNlIERvdWJsZXRGaW5kZXIgaXMgaW5zZW5zaXRpdmUgdG8gaG9tb3R5cGljIGRvdWJsZXRzIHRoZSBlc3RpbWF0aW9uIHByb2Nlc3MgaXMgZW50aXJlbHkgYmFzZWQgb24gZXN0aW1hdGVkIGZyZXF1ZW5jeSB3aXRoaW4gY2x1c3RlcnMsIGFuZCBoaWdobHkgc3ViamVjdCB0byBpbnB1dCBwYXJhbWV0ZXJzLiBUaGUgcGFja2FnZSBhdXRob3JzIGNvbnNpZGVyIGRvdWJsZXQgbnVtYmVyIGVzdGltYXRlcyBiYXNlZCBvbiBQb2lzc29uIHN0YXRpc3RpY3Mgd2l0aCBhbmQgd2l0aG91dCBob21vdHlwaWMgZG91YmxldCBwcm9wb3J0aW9uIGFkanVzdG1lbnQgdG8gJ2Jvb2tlbmQnIHRoZSByZWFsIGRldGVjdGFibGUgZG91YmxldCByYXRlLCBob3dldmVyIGluIHRoZXNlIGNhc2VzIHdoZXJlIHdlIHNlZSBhIHJhbmdlIGZyb20gMCAod2l0aG91dCBob21vdHlwaWMpIHRocm91Z2ggMjUlIGNlbGwgY291bnQgKHRoZSB2YWx1ZSB1c2VkIHRvIGVzdGltYXRlIGhvbW90eXBpYyBwb3B1bGF0aW9ucykgdGhhdCB0aGlzIHBhY2thZ2UgaGFzIGlkZW50aWZpZWQgbm8gYWN0dWFsIGRvdWJsZXRzLiBJbiByZXNwb25zZSB0byB0aGlzIGZpbmRpbmcgd2UgYXJlIHByb2NlZWRpbmcgd2l0aCB0aGlzIGFuYWx5c2lzIHdpdGhvdXQgYWRqdXN0aW5nIGZvciBkb3VibGV0IHNwZWNpZXMgY2VsbHMuIEZ1bGwgcmVzdWx0cyBjYW4gYmUgZm91bmQgb24gaW5kaXZpZHVhbCBkb3VibGV0IGZpbmRlciByZXBvcnRzLgoKYGBge2Jhc2ggZWNobz1GQUxTRX0KdHJlZSBkYXRhL2RvdWJsZXQtZmluZGVyLXJlcG9ydHMvCmBgYAoKIyMgTWFpbiBTZXVyYXQgb2JqZWN0IHByb2Nlc3NvcgoKQWZ0ZXIgaW5kaXZpZHVhbCBzYW1wbGVzIHdlcmUgaW5nZXN0ZWQsIGZpbHRlcmVkIGFuZCBjb25zaWRlcmVkIGZvciBkb3VibGV0IGV4Y2x1c2lvbiB0aGV5IHdlcmUgYWdncmVnYXRlZCBpbnRvIGEgc2luZ2xlIHNldXJhdCBvYmplY3QgYW5kIG5vcm1hbGl6ZWQuIFRoaXMgcHJvY2VzcyB3YXMgaW1wbGVtZW50ZWQgYXMgYGBgY29kZS8wMWMtbWVyZ2UuUmBgYC4gUHJvY2Vzc2luZyBpbmNsdWRlZCB0aGUgZm9sbG93aW5nIG1ham9yIHN0ZXBzOgoKMS4gTWVyZ2UgaW50byBhIHNpbmdsZSBzZXVyYXQKMi4gU2NvcmUgIGVhY2ggY2VsbCBmb3IgUyBhbmQgRzJNIGNlbGwgY3ljbGUgZWZmZWN0cyB0aGF0IGFyZSBpbmNsdWRlZCBpbiB0aGUgcmVncmVzc2lvbi9ub3JtYWxpemF0aW9uIHN0ZXBzLiBTZWUgYGBgY29kZS9jZWxsLWN5Y2xlLXRlc3RpbmcuUmBgYCBhbmQgQXByIDEsIDIwMjEgcHJlc2VudGF0aW9uIGZvciBkZXRhaWxzLiAKMy4gTm9ybWFsaXplRGF0YSwgRmluZFZhcmlhYmxlRmVhdHVyZXMsIFNjYWxlRGF0YQo0LiBSdW5QQ0EgZm9sbG93ZWQgYnkgRWxib3cgcGxvdCB0byBpZGVudGlmeSBpbXBvcnRhbnQgcHJpbmNpcGFsIGNvbXBvbmVudHMKICAgIC0gIVtdKGRhdGEvcGxvdHMvcGNhLXNjYXR0ZXJwbG90cy5wbmcpCiAgICAtICFbXShkYXRhL3Bsb3RzL2VsYm93LnBuZykKNS4gUnVuVU1BUCBmb2xsd2VkIGJ5IERpbVBsb3QgCiAgICAtICFbXShkYXRhL3Bsb3RzL3VtYXAtYnktc2FtcGxlLnBuZykKNi4gSWRlbnRpZnkgb3B0aW1hbCBjbHVzdGVyIHJlc29sdXRpb24gdXNpbmcgY2x1c3RyZWUKICAgIC0gIVtdKGRhdGEvcGxvdHMvY2x1c3RyZWUtcGxvdF9sb3ctZW5kLnBuZykKICAgIC0gIVtdKGRhdGEvcGxvdHMvdW1hcC0wLjAzLnBuZykKNy4gT3V0cHV0IGZyb20gdGhpcyBtYWluIHByb2Nlc3NpbmcgaXMgc3RvcmVkIGFzIGBgYG9iamVjdHMvZmlsdGVyZWQtbWVyZ2VkLXVtYXAuUkRTYGBgCgojIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKT25jZSBhbiBvcHRpbWFsIFNldXJhdCByZXNvbHV0aW9uIGhhZCBiZWVuIHNlbGVjdGVkICgwLjAzKSwgd2UgcmFuIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gYW5hbHlzaXMgaW4gU2V1cmF0IHVzaW5nIHRoZSBGaW5kTWFya2VycyBmdW5jdGlvbiBpbiBTZXVyYXQuIFRoaXMgd2FzIHBlcmZvcm1lZCBmb3IgZWFjaCBjbHVzdGVyIGluIGEgY2x1c3Rlci12cy1hbGwgY29udHJhc3QgbW9kZWwuIFNpbmNlIGEgbGlzdCBvZiB0YXJnZXRlZCBnZW5lcyB3YXMgbm90IGV4cGxpY2l0bHkgcHJvdmlkZWQgd2UgcmVwb3J0IHRoZSB0b3AgMjAgZ2VuZXMgcGVyIGNsdXN0ZXIuIAoKYGBge2Jhc2h9CmxzIGRhdGEvcGxvdHMvZGV4LXRvcC1kb3RwbG90KgpgYGAKCiMjIEdlbmVyYWwgZW5yaWNobWVudCBhbmFseXNpcwoKV2UgZm9sbG93ZWQtdXAgdGhlIERHRSBhbmFseXNpcyB3aXRoIG92ZXItcmVwcmVzZW50YXRpb24gYW5hbHlzaXMgdXNpbmcgbXNpZ2RiIGFuZCBjbHVzdGVycHJvZmlsZXIgaW4gUiBleHBsb3JpbmcgdGhlIEdPIGdlbmUgc2V0cyBhbmQgS0VHRy4gVGhpcyB3b3JrIHdhcyBkZWZpbmVkIGJ5IHRoZSBgYGBjb2RlLzA2LWVucmljaHIuUmBgYCBzY3JpcHQgYW5kIGluY2x1ZGVzIG1zaWdkYiBjYXRlZ29yaWVzICJLRUdHIiwgIkM1IihHbyB0ZXJtcykgYXMgd2VsbCBhcyBtb2R1bGVzIGRlZmluZWQgZm9yIHRoZSBpUFNDIGNsdXN0ZXIgcHJvZmlsZXIgdG9vbCBhdCBOQ0FUcy4gUmVzdWx0cyBhcmUgc3VtbWFyaXplZCBvbiB0aGUgYGBgZGF0YS90YWJsZS9lbnJpY2hlZC1zZXRzLnRzdmBgYAoKCmBgYHtyfQpyZWFkX3RzdigiZGF0YS90YWJsZXMvZW5yaWNoZWQtc2V0cy50c3YiLCBjb2xfdHlwZXMgPSBjb2xzKAogIGNsdXN0ZXIgPSBjb2xfZG91YmxlKCksCiAgaGl0cyA9IGNvbF9kb3VibGUoKSwKICBJRCA9IGNvbF9jaGFyYWN0ZXIoKSwKICBEZXNjcmlwdGlvbiA9IGNvbF9jaGFyYWN0ZXIoKSwKICBHZW5lUmF0aW8gPSBjb2xfY2hhcmFjdGVyKCksCiAgQmdSYXRpbyA9IGNvbF9jaGFyYWN0ZXIoKSwKICBwdmFsdWUgPSBjb2xfZG91YmxlKCksCiAgcC5hZGp1c3QgPSBjb2xfZG91YmxlKCksCiAgcXZhbHVlID0gY29sX2RvdWJsZSgpLAogIGdlbmVJRCA9IGNvbF9jaGFyYWN0ZXIoKSwKICBDb3VudCA9IGNvbF9kb3VibGUoKSApKSAlPiUgCiAgc2xpY2UoMToxMCkgJT4lIAogIHNlbGVjdCgtZ2VuZUlEKQpgYGAKCmBgYHtiYXNofQpscyBkYXRhL3Bsb3RzL2dvKgpscyBkYXRhL3Bsb3RzL2tlZ2cqCmBgYAoKCiMjIE1vZHVsZSBjb252ZXJzaW9uIGFuZCBzY29yaW5nCgpMYXN0bHksIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBpZGVudGl0eSBvciBjZWxsIHR5cGUgZm9yIGVhY2ggY2x1c3Rlciwgd2UgcmFuIFNldXJhdOKAmXMgQWRkTW9kdWxlU2NvcmUgZnVuY3Rpb24sIHVzaW5nIE5DQVRT4oCZIGxpc3Qgb2Yga25vd24gY2VsbCBtYXJrZXJzIGZyb20gYSBwcmV2aW91c2x5IGNyZWF0ZWQgaVBTQyBwcm9maWxlciBmb3IgZWFjaCBjZWxsIHNlcGFyYXRpb24gYXBwcm9hY2guIFRoZSBBZGRNb2R1bGVTY29yZSBjYWxjdWxhdGVzIHRoZSBhdmVyYWdlIGV4cHJlc3Npb24gZm9yIGVhY2ggY2x1c3RlciBzdWJ0cmFjdGVkIGJ5IHRoZSBhZ2dyZWdhdGVkIGV4cHJlc3Npb24gb2YgY29udHJvbCBmZWF0dXJlIHNldHMuIFBvc2l0aXZlIGV4cHJlc3Npb24gbGV2ZWxzIGluZGljYXRlIGEgaGlnaGVyIGV4cHJlc3Npb24gbGV2ZWwgdGhhbiByYW5kb20uIFdlIHdpbGwgdXNlIHRoZSBleHByZXNzaW9uIGxldmVscyB0byBicm9hZGx5IGFzc2lnbiBlYWNoIGNsdXN0ZXIgdG8gcG90ZW50aWFsIGlkZW50aXRpZXMgKGNlbGwgdHlwZSkuIAoKYGBge2Jhc2h9CmxzIGRhdGEvcGxvdHMvaXBzYyoKYGBgCgojIyBUcmFqZWN0b3J5IGluZmVyZW5jZQoKTGFzdGx5LCB3ZSByYW4gU2xpbmdzaG90IGZvciBzaW5nbGUtY2VsbCB0cmFqZWN0b3J5IGFuYWx5c2lzLiBUaGUgZ29hbCBvZiBzbGluZ3Nob3QgaXMgdG8gdXNlIGNsdXN0ZXJzIG9mIGNlbGxzIHRvIHVuY292ZXIgZ2xvYmFsIHN0cnVjdHVyZSBhbmQgY29udmVydCB0aGVzZSB0byBwc2V1ZG90aW1lLiBUbyBhY2NvbXBsaXNoIHRoaXMgd29yayB3ZSB1dGlsaXplZCB0aGUgKmR5bnZlcnNlKiBzZXQgb2YgUi1wYWNrYWdlcyBpbiBjb25qdW5jdGlvbiB3aXRoIHByb3ZpZGVkIGNvZGUgZnJvbSBDbGFpcmUgTWFsbGV5IHRvIHJ1biBTbGluZ3Nob3QgYW5kIGV4dHJhY3QgcHNldWRvdGltZSBtZXRyaWNzLiAKClRoaXMgYW5hbHlzaXMgeWllbGRlZCBzb21lIHByb2R1Y3RpdmUgZmluZGluZ3MgYWNyb3NzIHRoZSBhbm5vdGF0ZWQgdW1hcCBjbHVzdGVycy4gVGhpcyByb3VnaGx5IGZvbGxvd2VkIGEgdHJhamVjdG9yeSBhbG9uZyBuZXVyb25hbCBwcmVjdXJzb3JzIChjbHVzdGVyIDEpLCBnbGlhbC9hc3RyYWwvU0dDIGNlbGxzIChjbHVzdGVyIDAsIHRoZSBsYXJnZXN0KSBhbmQgc3BsaXRzIGludG8gc2V2ZXJhbCB0eXBlcyBvZiBtYXR1cmluZyBub2NpY2VwdG9ycyAoY2x1c3RlciA1KSBhbmQgbGlrZWx5IGFsdGVybmF0aXZlIGRldmVsb3BtZW50YWwgbmV1cm9uYWwgY2VsbCB0eXBlcyAoY2x1c3RlcnMgMyw2KSAKCiFbXShkYXRhL3Bsb3RzL3RpLXVtYXAtY2x1c3Rlci5wbmcpCldoZW4gYW4gdW5zdXBlcnZpc2VkIHBzZXVkb3RpbWUgZXN0aW1hdGlvbiBpcyBwbG90dGVkIG9uIHRoZXNlIGNlbGxzIHdlIHNlZSBhIG5hdHVyYWwgcHJvZ3Jlc3Npb24uCgohW10oZGF0YS9wbG90cy90aS11bWFwLXBzZXVkb3RpbWUucG5nKQoKCiMjIFBzZXVkb3R5cGUtYmFzZWQgZGlmZmVyZW50aWFsIG1vZGVsaW5nCgpBZnRlciBTbGluZ3Nob3Qgd2FzIHJ1biwgd2UgZXhwbG9yZWQgdGVtcG9yYWxseSBleHByZXNzZWQgZ2VuZXMgdXNpbmcgdGhlIHRyYWRlU2VxIHBhY2thZ2UuIEZvciBlYWNoIGdlbmUsIHdlIGZpdCBhIGdlbmVyYWwgYWRkaXRpdmUgbW9kZWwgKEdBTSkgdXNpbmcgYSBuZWdhdGl2ZSBiaW5vbWlhbCBub2lzZSBkaXN0cmlidXRpb24gdG8gbW9kZWwgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgcHNldWRvdGltZS4gQWZ0ZXIgcnVubmluZyB0aGUgR0FNIG1vZGVsLCB3ZSB0ZXN0ZWQgZm9yIHNpZ25pZmljYW50IGFzc29jaWF0aW9ucyBiZXR3ZWVuIGV4cHJlc3Npb24gYW5kIHBzZXVkb3RpbWUgdXNpbmcgdGhlIGFzc29jaWF0aW9uVGVzdC4gCg==